package org.sl.flvplayer.main {
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.XMLSocket;

	public class SOS {
		
		public static const CONFIG_LEVEL		:String = "config";
		public static const FINEST_LEVEL		:String = "finest";
		public static const FINER_LEVEL			:String = "finer";
		public static const SYSTEM_LEVEL		:String = "system";
		public static const SEVERE_LEVEL		:String = "severe";
		public static const TEMP_LEVEL			:String = "temp";
		public static const TRACE_LEVEL			:String = "trace";
		public static const FINE_LEVEL			:String = "fine";
		public static const FLASH_TRACE_LEVEL	:String = "flash trace";
		public static const WARNING_LEVEL		:String = "warning";
		public static const ERROR_LEVEL			:String = "error";
		public static const FATAL_LEVEL			:String = "fatal";
		public static const INFO_LEVEL			:String = "info";
		public static const WARN_LEVEL			:String = "warn";
		public static const DEBUG_LEVEL			:String = "debug";
		
		private const ALLOW_DEBUG	:Boolean = true; // change to false when Debugger not needed.
		
		private var socket 			:XMLSocket; 
		 
		public function SOS() {
			socket = new XMLSocket();
			socket.addEventListener(Event.CONNECT, onConnect);
			socket.addEventListener(IOErrorEvent.IO_ERROR, onError);
			socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
			if(ALLOW_DEBUG) {
				try {
					socket.connect("localhost", 4444);
				} catch (error : SecurityError) {
					trace("SecurityError in SOSAppender: " + error);
				}
			}
		}
		 
		private function onError(event : Event) : void {
			trace("Error in SOSAppender: " + event);
		}
		
		private function onConnect(event : Event) : void {
			alert("Flash Connected");
		}
		
		private function alertLevel(p_message :String, p_level :String) :void {
			if(ALLOW_DEBUG) socket.send("!SOS<showMessage key='" + p_level + "'>" + p_message + "</showMessage>\n");
		}
		
		private function traceObject(p_object :Object, p_tabLevel :Number = 1) :String {
			var tabs :String = "";
			for (var t:Number = 0; t < p_tabLevel; t++) tabs += "\t";
			
			var object :Array = new Array();
			var type :String;
			var value :Object;
			for (var i :String in p_object) {
				type = getType(p_object[i]);
				if (type == "(Array)" || type == "(Object)") {
					object.push(tabs + i + ":" + getType(p_object[i]) + "\n" + traceObject(p_object[i], p_tabLevel + 1));
				} else {
					value = (type == "(int)") ? p_object[i].valueOf() : p_object[i];
					object.push(tabs + i + ":" + value + getType(p_object[i]));
				}
			}
			return object.join("\n");
		}
		
		private function getType(p_object :Object) :String {
			switch(typeof(p_object)) {
				case "boolean":
					return "(Boolean)";
				
				case "function":
					return "(Function)";
				
				case "string":
					return "(String)";
				
				case "object":
					if (p_object is Array) return "(Array)";
					return "(Object)";
				
				case "number":
					if (p_object is int) return "(int)";
					if (p_object is uint) return "(uint)";
					return "(Number)";
				
				case "xml":
					if (p_object is XMLList) return "(XMLList)";
					return "(XML)";
			}
			return "(Object)";
		}
		
		public function alert(p_message :String) :void {
			if(ALLOW_DEBUG) socket.send(p_message);
		}
		
		public function config(p_message :String, p_object :Object = null) :void {
			if (p_object == null) alertLevel(p_message as String, CONFIG_LEVEL);
			else extendedMessage(p_message, p_object, CONFIG_LEVEL);
		}
		
		public function finest(p_message :String, p_object :Object = null) :void {
			if (p_object == null) alertLevel(p_message as String, FINEST_LEVEL);
			else extendedMessage(p_message, p_object, FINEST_LEVEL);
		}
		
		public function finer(p_message :String, p_object :Object = null) :void {
			if (p_object == null) alertLevel(p_message as String, FINER_LEVEL);
			else extendedMessage(p_message, p_object, FINER_LEVEL);
		}
		
		public function system(p_message :String, p_object :Object = null) :void {
			if (p_object == null) alertLevel(p_message as String, SYSTEM_LEVEL);
			else extendedMessage(p_message, p_object, SYSTEM_LEVEL);
		}
		
		public function severe(p_message :String, p_object :Object = null) :void {
			if (p_object == null) alertLevel(p_message as String, SEVERE_LEVEL);
			else extendedMessage(p_message, p_object, SEVERE_LEVEL);
		}
		
		public function temp(p_message :String, p_object :Object = null) :void {
			if (p_object == null) alertLevel(p_message as String, TEMP_LEVEL);
			else extendedMessage(p_message, p_object, TEMP_LEVEL);
		}
		
		public function traceMsg(p_message :String, p_object :Object = null) :void {
			if (p_object == null) alertLevel(p_message as String, TRACE_LEVEL);
			else extendedMessage(p_message, p_object, TRACE_LEVEL);
		}
		
		public function fine(p_message :String, p_object :Object = null) :void {
			if (p_object == null) alertLevel(p_message as String, FINE_LEVEL);
			else extendedMessage(p_message, p_object, FINE_LEVEL);
		}
		
		public function flash_trace(p_message :String, p_object :Object = null) :void {
			if (p_object == null) alertLevel(p_message as String, FLASH_TRACE_LEVEL);
			else extendedMessage(p_message, p_object, FLASH_TRACE_LEVEL);
		}
		
		public function warning(p_message :String, p_object :Object = null) :void {
			if (p_object == null) alertLevel(p_message as String, WARNING_LEVEL);
			else extendedMessage(p_message, p_object, WARNING_LEVEL);
		}
		
		public function error(p_message :String, p_object :Object = null) :void {
			if (p_object == null) alertLevel(p_message as String, ERROR_LEVEL);
			else extendedMessage(p_message, p_object, ERROR_LEVEL);
		}
		
		public function fatal(p_message :String, p_object :Object = null) :void {
			if (p_object == null) alertLevel(p_message as String, FATAL_LEVEL);
			else extendedMessage(p_message, p_object, FATAL_LEVEL);
		}
		
		public function info(p_message :String, p_object :Object = null) :void {
			if (p_object == null) alertLevel(p_message as String, INFO_LEVEL);
			else extendedMessage(p_message, p_object, INFO_LEVEL);
		}
		
		public function warn(p_message :String, p_object :Object = null) :void {
			if (p_object == null) alertLevel(p_message as String, WARN_LEVEL);
			else extendedMessage(p_message, p_object, WARN_LEVEL);
		}
		
		public function debug(p_message :String, p_object :Object = null) :void {
			if (p_object == null) alertLevel(p_message as String, DEBUG_LEVEL);
			else extendedMessage(p_message, p_object, DEBUG_LEVEL);
		}
		
		public function extendedMessage(p_message :String, p_object :Object, p_level :String) :void {
			var message :String = "!SOS<showFoldMessage key='" + p_level + "'>";
			message += "<title>" + p_message + "</title>";
			message += "<message>" + traceObject(p_object) + "</message>";
			message += "</showFoldMessage>";
			if(ALLOW_DEBUG) socket.send(message);
			
		}
		
	}
	
}